//
//  String+Extension.swift
//  SwiftProject
//
//  Created by qindong on 2021/3/11.
//

import Foundation
import CoreImage

extension String {
    // MARK: - 转NSString
    var asNSString : NSString {
        self as NSString
    }

    var cropTime : String {
        substring(to: 10)
    }
    
    // MARK: - string内容是否是纯数字
    var isNumber : Bool {
        if isEmpty {
            return false
        }
        let regex = "[0-9]*"
        let pred = NSPredicate(format: "SELF MATCHES %@", regex)
        if pred.evaluate(with: self) {
            return true
        }
        return false
    }

    // MARK: - 同一给string添加格式信息
    func addParagraphStyle(_ lineSpacing : CGFloat = 0, _ firstLineHeadIndent : CGFloat = 0, _ lineBreakModel : NSLineBreakMode = .byWordWrapping, _ foregroundColor : UIColor, _ font : UIFont, kern : Float = 0, alignment : NSTextAlignment = .left) -> NSMutableAttributedString {
        let attributedString = NSMutableAttributedString(string: self)
        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.lineSpacing = lineSpacing
        paragraphStyle.lineBreakMode = .byWordWrapping;
        paragraphStyle.alignment = alignment
        paragraphStyle.firstLineHeadIndent = firstLineHeadIndent
        let attributes : [NSAttributedString.Key : Any] = [.foregroundColor : foregroundColor, .font : font, .paragraphStyle : paragraphStyle, .kern : kern]
        attributedString.addAttributes(attributes, range: NSRange(location: 0, length: attributedString.length))
        return attributedString
    }
    
    // MARK: - 用信号量获取网络图片的尺寸
    var getImageSize : CGSize {
        var size : CGSize = .minSize
        guard count != 0 else {
            return size
        }
        let dispatchSemaphore = DispatchSemaphore(value: 0)

        let url = URL(string: self)!
        let request = URLRequest(url: url)
        let pathExtendsion = url.pathExtension.lowercased()
        if pathExtendsion == "png" {
            size = getPNGImageSize(request: request)
        } else if pathExtendsion == "gif" {
            size = getGIFImageSize(request: request)
        } else {
            size = getJPGImageSize(request: request)
        }
        
        if size == .zero {
            URLSession.shared.dataTask(with: request) { (data, response, error) in
                if error == nil {
                    let image : UIImage? = UIImage.init(data: data!)
                    if image != nil {
                        size = image!.size
                    }
                }
                dispatchSemaphore.signal()
            }.resume()
            _ = dispatchSemaphore.wait(timeout: .distantFuture)
        }
        return size
    }
    
    // MARK: - 获取视频地址的第一帧图片
    var getVideoPreViewImage : UIImage? {
        if isEmpty { return nil }
        let asset = AVURLAsset(url: URL(string: self)!)
        let assetGen = AVAssetImageGenerator(asset: asset)
        assetGen.appliesPreferredTrackTransform = true
        let time = CMTime(seconds: 0, preferredTimescale: 600)
        var actualTime = CMTime()
        let image = try! assetGen.copyCGImage(at: time, actualTime: &actualTime)
        let videoImage = UIImage(cgImage: image)
        return videoImage
    }
    
    // MARK: - 获取PNG图片的大小
    private func getPNGImageSize(request : URLRequest) -> CGSize {
        var request = request
        var imageData : NSData?
        let dispatchSemaphore = DispatchSemaphore(value: 0)
        request.setValue("bytes=16-23", forHTTPHeaderField: "Range")
        URLSession.shared.dataTask(with: request) { (data, response, error) in
            imageData = NSData(data: data!)
            dispatchSemaphore.signal()
        }.resume()
        _ = dispatchSemaphore.wait(timeout: .distantFuture)
        
        if imageData!.count == 8 {
            var w1:Int = 0
            var w2:Int = 0
            var w3:Int = 0
            var w4:Int = 0
            
            imageData!.getBytes(&w1, range: NSMakeRange(0, 1))
            imageData!.getBytes(&w2, range: NSMakeRange(1, 1))
            imageData!.getBytes(&w3, range: NSMakeRange(2, 1))
            imageData!.getBytes(&w4, range: NSMakeRange(3, 1))
            
            let w = (w1 << 24) + (w2 << 16) + (w3 << 8) + w4
            var h1:Int = 0
            var h2:Int = 0
            var h3:Int = 0
            var h4:Int = 0
            imageData!.getBytes(&h1, range: NSMakeRange(4, 1))
            imageData!.getBytes(&h2, range: NSMakeRange(5, 1))
            imageData!.getBytes(&h3, range: NSMakeRange(6, 1))
            imageData!.getBytes(&h4, range: NSMakeRange(7, 1))
            let h = (h1 << 24) + (h2 << 16) + (h3 << 8) + h4

            return CGSize(width: CGFloat(w), height: CGFloat(h));
        }
        return .zero
    }
    
    // MARK: - 获取GIF图片的大小
    private func getGIFImageSize(request : URLRequest) -> CGSize {
        var request = request
        let dispatchSemaphore = DispatchSemaphore(value: 0)
        request.setValue("bytes=6-9", forHTTPHeaderField: "Range")
        var imageData : NSData?
        URLSession.shared.dataTask(with: request) { (data, response, error) in
            imageData = NSData(data: data!)
            dispatchSemaphore.signal()
        }.resume()
        _  = dispatchSemaphore.wait(timeout: .distantFuture)
        if imageData!.count == 4 {
            var w1:Int = 0
            var w2:Int = 0

            imageData!.getBytes(&w1, range: NSMakeRange(0, 1))
            imageData!.getBytes(&w2, range: NSMakeRange(1, 1))

            let w = w1 + (w2 << 8)
            var h1:Int = 0
            var h2:Int = 0

            imageData!.getBytes(&h1, range: NSMakeRange(2, 1))
            imageData!.getBytes(&h2, range: NSMakeRange(3, 1))
            let h = h1 + (h2 << 8)

            return CGSize(width: CGFloat(w), height: CGFloat(h));
        }
        return .zero
    }
    
    // MARK: - 获取JPG图片的大小
    private func getJPGImageSize(request : URLRequest) -> CGSize {
        var request = request
        let dispatchSemaphore = DispatchSemaphore(value: 0)
        request.setValue("bytes=0-209", forHTTPHeaderField: "Range")
        var imageData : NSData?
        URLSession.shared.dataTask(with: request) { (data, response, error) in
            imageData = NSData(data: data!)
            dispatchSemaphore.signal()
        }.resume()
        _ = dispatchSemaphore.wait(timeout: .distantFuture)
        if imageData!.count <= 0x58 {
            return .zero
        }
        if imageData!.count < 210 {
            var w1:Int = 0
            var w2:Int = 0

            imageData!.getBytes(&w1, range: NSMakeRange(0x60, 0x1))
            imageData!.getBytes(&w2, range: NSMakeRange(0x61, 0x1))

            let w = (w1 << 8) + w2
            var h1:Int = 0
            var h2:Int = 0

            imageData!.getBytes(&h1, range: NSMakeRange(0x5e, 0x1))
            imageData!.getBytes(&h2, range: NSMakeRange(0x5f, 0x1))
            let h = (h1 << 8) + h2

            return CGSize(width: CGFloat(w), height: CGFloat(h))
        } else {
            var word = 0x0
            imageData!.getBytes(&word, range: NSMakeRange(0x15, 0x1))
            if word == 0xdb {
                imageData!.getBytes(&word, range: NSMakeRange(0x5a, 0x1))
                if word == 0xdb {
                    var w1:Int = 0
                    var w2:Int = 0

                    imageData!.getBytes(&w1, range: NSMakeRange(0xa5, 0x1))
                    imageData!.getBytes(&w2, range: NSMakeRange(0xa6, 0x1))

                    let w = (w1 << 8) + w2
                    var h1:Int = 0
                    var h2:Int = 0

                    imageData!.getBytes(&h1, range: NSMakeRange(0xa3, 0x1))
                    imageData!.getBytes(&h2, range: NSMakeRange(0xa4, 0x1))
                    let h = (h1 << 8) + h2

                    return CGSize(width: CGFloat(w), height: CGFloat(h));
                } else {
                    var w1:Int = 0
                    var w2:Int = 0

                    imageData!.getBytes(&w1, range: NSMakeRange(0x60, 0x1))
                    imageData!.getBytes(&w2, range: NSMakeRange(0x61, 0x1))

                    let w = (w1 << 8) + w2
                    var h1:Int = 0
                    var h2:Int = 0

                    imageData!.getBytes(&h1, range: NSMakeRange(0x5e, 0x1))
                    imageData!.getBytes(&h2, range: NSMakeRange(0x5f, 0x1))
                    let h = (h1 << 8) + h2

                    return CGSize(width: CGFloat(w), height: CGFloat(h));
                }
            } else {
                return .zero
            }
        }
    }
    
    // MARK: - 用类名找class快捷方法 由于swift用类名找class需要拼接项目名称
    public var classOfName : AnyClass {
        NSClassFromString("\(ProjectName).\(self)")!
    }
    
    // MARK: - 解析Url里的参数 Dictionary返回
    public var parseUrlParameters : [String : String]? {
        guard let range = range(of: "?") else { return nil }
        var parameters : [String : String] = [:]
        let parametersString = String(self[range.upperBound...])
        if parametersString.contains("&") {
            let urlCompinents = parametersString.components(separatedBy: "&")
            for keyValuePair in urlCompinents {
                let pairComponents = keyValuePair.components(separatedBy: "=")
                let key : String? = pairComponents.first?.removingPercentEncoding
                let value : String? = pairComponents.last?.removingPercentEncoding
                if key == nil || value == nil { continue }
//                let existValue = parameters[key!]
//                if existValue != nil {
//                    if existValue! is Array<Any> {
//                        var items : Array = existValue as! Array<Any>
//                        items.append(value as Any)
//                        parameters.updateValue(items, forKey: key!)
//                    } else {
//                        parameters.updateValue([existValue,value], forKey: key!)
//                    }
//                } else {
                    parameters.updateValue(value!, forKey: key!)
//                }
            }
        } else {
            let pairComponents = parametersString.components(separatedBy: "=")
            if pairComponents.count == 1 { return nil }
            let key : String? = pairComponents.first?.removingPercentEncoding
            let value : String? = pairComponents.last?.removingPercentEncoding
            if key == nil || value == nil { return nil }
            parameters.updateValue(value!, forKey: key!)
        }
        return parameters
    }
    
    // MARK: - 获取文字的宽度
    func getStringWidth(font: UIFont) -> CGFloat {
        self.size(withAttributes: [.font: font]).width
    }

    // MARK: - 获取文字的高度(需要一个最大宽度)
    func getStringHeight(font: UIFont, maxWidth: CGFloat) -> CGFloat {
        self.boundingRect(with: CGSize(width: maxWidth, height: CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [.font: font], context: nil).height
    }
    
    // MARK: - string转double
    var stringToNumber : Double {
        var number: Double = 0
        if let num = Double(self) {
            number = num
        }
        return number
    }
    
    // MARK: - string转百分比
    var stringToPercent : Double {
        var number: Double = 0
        if let num = Double(self) {
            number = num
        }
        return number / 100
    }
    
    // MARK: - string转CGFloat
    var stringToFloat : CGFloat {
        CGFloat(stringToNumber)
    }
    
    // MARK: - json字符串转字典
    var dictionaryValue : [String : Any] {
        if let dict = try? JSONSerialization.jsonObject(with: data(using: .utf8)!, options: .mutableContainers) as? [String : Any] {
            return dict
        }
        return [:]
    }
    
    // MARK: - json字符串转数组
    var arrayValue : [Any] {
        if let array = try? JSONSerialization.jsonObject(with: data(using: .utf8)!, options: .mutableContainers) as? [Any] {
            return array
        }
        return []
    }

    // MARK: - json字符串转对象
    func modelValue<T : HandyJSON>(_ modelType : T.Type) -> T? {
        if let value = JSONDeserializer<T>.deserializeFrom(json: self) {
            return value
        }
        return nil
    }

    // MARK: - json（数组）字符串转对应对象数组
    func modelArray<T : HandyJSON>(_ modelType : T.Type) -> [T] {
        if let array = try? JSONSerialization.jsonObject(with: data(using: .utf8)!, options: .mutableContainers) as? [[String : Any]] {
            return array.map{ JSONDeserializer<T>.deserializeFrom(dict: $0)! }
        }
        return []
    }
    
    // MARK: - 验证url字符串
    var isValidUrl : Bool {
        let link : String = (removingPercentEncoding?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))!
        return URL(string: link) != nil
    }
    
    // MARK: - 验证邮箱
    var validateEmail : Bool {
        let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
        let emailTest = NSPredicate(format: "SELF MATCHES %@", emailRegex)
        return emailTest.evaluate(with: self)
    }
    
    // MARK: - 验证手机号
    var isValidPhone : Bool {
        let pattern2 = "^1[0-9]{10}$"
        if NSPredicate(format: "SELF MATCHES %@", pattern2).evaluate(with: self) {
            return true
        }
        return false
    }

    // MARK: - 生成随机字符串
    static func random(_ count: Int) -> String {
        let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        let len = UInt32(letters.length)
        var randomString = ""
        for _ in 0..<count {
            let rand = arc4random_uniform(len)
            var nextChar = letters.character(at: Int(rand))
            randomString += NSString(characters: &nextChar,length: 1) as String
        }
        return randomString
    }

    // MARK: - 生成随机数字
    static func randomNumber(_ count: Int) -> String {
        let letters : NSString = "0123456789"
        let len = UInt32(letters.length)
        var randomString = ""
        for _ in 0..<count {
            let rand = arc4random_uniform(len)
            var nextChar = letters.character(at: Int(rand))
            randomString += NSString(characters: &nextChar,length: 1) as String
        }
        return randomString
    }
    
    // MARK: - Base64加密
    var base64Encoding : String {
        if let data = data(using: .utf8) {
            return data.base64EncodedString()
        }
        return ""
    }
    
    // MARK: - Base64解码
    var base64Decode : String {
        if let data = Data(base64Encoded: self) {
            return String(data: data, encoding: .utf8)!
        }
        return ""
    }
    
    // MARK: - 字符串生成二维码      需要库pod 'LBXScan/LBXZXing'
//    func createQCCodeImage(_ size : CGSize, _ centerImage : UIImage? = nil) -> UIImage {
//        let writer = ZXMultiFormatWriter()
//        let hints = ZXEncodeHints.hints() as! ZXEncodeHints
//        hints.encoding = String.Encoding.utf8.rawValue
//        hints.dataMatrixShape = ZXDataMatrixSymbolShapeHintForceSquare
//        hints.margin = 0
//        hints.errorCorrectionLevel = ZXQRCodeErrorCorrectionLevel.errorCorrectionLevelH()
//        let result : ZXBitMatrix = try! writer.encode(self, format: kBarcodeFormatQRCode, width: Int32(Int(size.width)), height: Int32(size.height), hints: hints)
//        let array : ZXIntArray = result.enclosingRectangle()
//        let res : ZXBitMatrix = ZXBitMatrix(width: Int32(array.array[2] + 1), height: Int32(array.array[3] + 1))
//        res.clear()
//        for i in 0..<array.array[2] + 1 {
//            for j in 0..<array.array[3] + 1 {
//                if result.getX(i + array.array[0], y: j + array.array[1]) {
//                    res.setX(i, y: j)
//                }
//            }
//        }
//        let image : ZXImage = ZXImage(matrix: res)
//        let codeImage = UIImage(cgImage: image.cgimage)
//        if centerImage != nil {
//            return codeImage.addSubImage(codeImage, centerImage!)
//        }
//        return codeImage
//    }
    
    // MARK: - 阿里云oss获取图片尺寸
    var getAliOSSImageSize : CGSize {
        var size : CGSize = .minSize
        let dispatchSemaphore = DispatchSemaphore(value: 0)
        let request : URLRequest = URLRequest(url: URL(string: self + "?x-oss-process=image/info")!)
        URLSession.shared.dataTask(with: request) { (data, response, error) in
            if error == nil {
                if let dict = try? JSONSerialization.jsonObject(with: data!, options: []) as? [String : [String : String]] {
                    size.height = dict["ImageHeight"]!["value"]!.stringToFloat
                    size.width = dict["ImageWidth"]!["value"]!.stringToFloat
                }
            }
            dispatchSemaphore.signal()
        }.resume()
        _ = dispatchSemaphore.wait(timeout: .distantFuture)
        return size
    }

    // MARK: - 复制字符串到剪切板
    func copyString(_ tipText : String = "内容已复制到粘贴板") {
        let pasteboard = UIPasteboard.general
        pasteboard.string = self
        if !tipText.isEmpty {
            QMUITips.show(withText: tipText)
        }
    }

    // MARK: - 给字符串中的指定字符串添加样式快捷方法
    func addAttributedString(_ keyString : String, _ keyColor : UIColor? = nil, _ keyFont : UIFont? = nil, _ defultColor : UIColor? = nil) -> NSMutableAttributedString {
        let attr = NSMutableAttributedString(string: self)
        if defultColor != nil {
            attr.addAttributes([.foregroundColor : defultColor!], range: NSRange(location: 0, length: count))
        }
        var attributes : [NSAttributedString.Key : Any] = [:]
        if keyFont != nil {
            attributes[.font] = keyFont!
        }
        if keyColor != nil {
            attributes[.foregroundColor] = keyColor!
        }
        attr.addAttributes(attributes, range: asNSString.range(of: keyString))
        return attr
    }

    // MARK: - 判断字符串是否包含链接
    var hasUrl : Bool {
        let regex = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|(www.[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)"
        do {
            let re = try NSRegularExpression.init(pattern: regex, options: .caseInsensitive)
            let array = re.matches(in: self, options: .reportProgress, range: NSMakeRange(0, count))
            if array.isEmpty {
                return false
            } else {
                return true
            }
        } catch {
            return false
        }
    }

    // MARK: - 判断字符串是否包含淘口令
    var isTKL : Bool {
        let emailRegex = "^[₳,$,¢,₴,€,₤,￥,＄,《]{1}\\w{11}[₳,$,¢,₴,€,₤,￥,＄,《]{1}$"
        let emailTest = NSPredicate(format: "SELF MATCHES %@", emailRegex)
        return emailTest.evaluate(with: self)
    }
    
    // MARK: - String使用下标截取字符串
    // MARK: - string[index] 例如："abcdefg"[3] // c
    subscript (i : Int) -> String {
        let startIndex1 = index(startIndex, offsetBy: i)
        let endIndex1 = index(startIndex, offsetBy: 1)
        return String(self[startIndex1 ..< endIndex1])
    }
    
    // MARK: - String使用下标截取字符串
    // MARK: - string[index..<index] 例如："abcdefg"[3..<4] // d
    subscript (r: Range<Int>) -> String {
        get {
            let startIndex1 = index(startIndex, offsetBy: r.lowerBound)
            let endIndex1 = index(startIndex, offsetBy: r.upperBound)
            return String(self[startIndex1 ..< endIndex1])
        }
    }
    // MARK: - String使用下标截取字符串
    // MARK: - string[index,length] 例如："abcdefg"[3,2] // de
    subscript (index : Int , length : Int) -> String {
        get {
            let startIndex1 = self.index(startIndex, offsetBy: index)
            let endIndex1 = self.index(startIndex, offsetBy: length)
            return String(self[startIndex1 ..< endIndex1])
        }
    }
    // MARK: - 截取 从头到i位置
    func substring(to : Int) -> String {
        self[0 ..< to]
    }
    // MARK: - 截取 从i到尾部
    func substring(from : Int) -> String {
        self[from ..< count]
    }
    
    // MARK: - string部分替换成*
    mutating func replaceStringWithAsterisk(from : Int, length : Int) -> String {
        if from + length > count {
            return self
        }
        let startIndex = self.index(startIndex, offsetBy: from)
        let endIndex = self.index(startIndex, offsetBy: length)
        let range = startIndex...endIndex
        var replaceStr = ""
        for _ in 0..<length {
            replaceStr += "*"
        }
        replaceSubrange(range, with: replaceStr)
        return self
    }
}

